package top.xmj.controller;

import cn.hutool.json.JSONUtil;
import cn.hutool.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.configurationprocessor.json.JSONException;
import org.springframework.stereotype.Component;
import top.xmj.domain.FriendBO;
import top.xmj.pojo.SubMessage;
import top.xmj.service.IFriendService;
import top.xmj.util.*;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;


/**
 *
 * @author 冰咖啡
 * @Date:2/12/2022 下午 9:36
 * @Description: websocket服务
 *
 */
@ServerEndpoint(value = "/websocket/{id}")
@Component
public class WebSocketServer {
    private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);
    /**
     * 记录当前在线连接数
     */
    public static final Map<String, Session> sessionMap = new ConcurrentHashMap<>();


    public List<FriendBO> users = null;

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("id") String id) throws JSONException {
        sessionMap.put(id, session);
        log.info("有新用户加入，id={}, 当前在线人数为：{}", id, sessionMap.size());
        JSONObject result = new JSONObject();
        IFriendService friendService =  ApplicationContextRegister.getApplicationContext().getBean(IFriendService.class);
        RedisUtil redisUtil =  ApplicationContextRegister.getApplicationContext().getBean(RedisUtil.class);
        users = friendService.getListByUserId(id);

        // 获取list中的数据
        Object resultObj = redisUtil.lGet("subMessage", 0, redisUtil.lGetListSize("subMessage"));
        // 将Object安全的转为List
        List<SubMessage> list = ObjectToOtherUtil.castList(resultObj, SubMessage.class);

        List<SubMessage> msgList = list.stream()
                .filter(d -> id.equals(d.getReceiverId()) || id.equals(d.getUserId()))
                .collect(Collectors.toList());

        result.put("msgList", msgList);
        result.put("users", users);
        sendMessage(JSONUtil.toJsonStr(result),session);
    }


    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(Session session, @PathParam("id") String id) {
        log.info("有一连接关闭，移除id={}的用户session, 当前在线人数为：{}", id, sessionMap.size());
        sessionMap.remove(id);
    }


    /**
     * 收到客户端消息后调用的方法
     * 后台收到客户端发送过来的消息
     * onMessage 是一个消息的中转站
     * 接受 浏览器端 socket.send 发送过来的 json数据
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message) throws JSONException {
        // 客户端发送的消息
        JSONObject jsReply = new JSONObject(message);
        Session toSession = sessionMap.get(jsReply.getStr("receiverId"));
        if (jsReply.getStr("receiverId")!=null) {
            // 获取推送方id
            String userId = jsReply.getStr("userId");
            // 获取被推送方id
            String receiverId = jsReply.getStr("receiverId");
            // 构造聊天记录实体类数据
            SubMessage subMessage = new SubMessage();
            subMessage.setAvatar(jsReply.getStr("avatar"));
            subMessage.setUserId(jsReply.getStr("userId"));
            subMessage.setUsername(jsReply.getStr("username"));
            subMessage.setReceiverId(jsReply.getStr("receiverId"));
            subMessage.setMsgText(jsReply.getStr("msgText"));
            subMessage.setStatus(1);
            subMessage.setCreateTime(DateFormatUtils.getDate(new Date(),"yyyy-MM-dd hh:mm:ss"));
            subMessage.setId(SnowflakeIdWorker.getSnowflakeId());
            // 将聊天记录对象保存到redis中
            RedisUtil redisUtil =  ApplicationContextRegister.getApplicationContext().getBean(RedisUtil.class);
            redisUtil.lSet("subMessage", subMessage,5000);
            // 发送消息至被推送方
            if(toSession!=null){
                this.sendMessage(JSONUtil.toJsonStr(subMessage), toSession);
            }
        }
    }

    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发生错误");
        error.printStackTrace();
    }
    /**
     * 服务端发送消息给客户端
     */
    private void sendMessage(String message, Session toSession) {
        try {
            log.info("服务端给客户端[{}]发送消息{}", toSession.getId(), message);
            toSession.getBasicRemote().sendText(message);
        } catch (Exception e) {
            log.error("服务端发送消息给客户端失败", e);
        }
    }
    /**
     * 服务端发送消息给所有客户端
     */
    private void sendAllMessage(String message) {
        try {
            for (Session session : sessionMap.values()) {
//                log.info("服务端给客户端[{}]发送消息{}", session.getId(), message);
                session.getBasicRemote().sendText(message);
            }
        } catch (Exception e) {
            log.error("服务端发送消息给客户端失败", e);
        }
    }

    /**
     *
     * @param message
     */
    private void sendOtherMessage(String message,Session sess) {
        try {
            for (Session session : sessionMap.values()) {
//                log.info("服务端给客户端[{}]发送消息{}", session.getId(), message);
                if(session != sess){
                    session.getBasicRemote().sendText(message);
                }
            }
        } catch (Exception e) {
            log.error("服务端发送消息给客户端失败", e);
        }
    }
}
